{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a9c11113-5a46-474d-abc4-c49e95c16684",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-13T05:20:52.497972400Z",
     "start_time": "2024-01-13T05:20:47.086906300Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "# 机器学习\n",
    "from sklearn.model_selection import train_test_split  # 划分训练集和测试集\n",
    "from sklearn.linear_model import LogisticRegressionCV  # 逻辑回归\n",
    "\n",
    "# 深度学习\n",
    "# tf.kears中使用的相关工具\n",
    "from keras.models import Sequential  # 用于模型搭建\n",
    "from keras.layers import Dense, Activation  # 构建模型的层和激活方法\n",
    "# from keras.utils import  to_categorical,plot_model  # 数据处理工具类\n",
    "from keras import utils\n",
    "\n",
    "# 在jupyter可以用，但是正在 pycharm就不能用\n",
    "# from tensorflow.keras.models import Sequential\n",
    "# from tensorflow.keras.layers import Dense,Activation\n",
    "# from tensorflow.keras import utils\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5463481f-1868-456f-8dce-adac5089ad4b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-13T05:20:58.500612100Z",
     "start_time": "2024-01-13T05:20:58.452623500Z"
    }
   },
   "outputs": [],
   "source": [
    "iris = pd.read_csv(\"D:\\\\data\\\\seaborn-data\\\\iris.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "iris"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "87a8283d62797747"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3134ffc0-7824-4dd6-9ba5-19c30dd5fc01",
   "metadata": {},
   "outputs": [],
   "source": [
    "sns.pairplot(iris, hue=\"species\")  # 目标值：hue=\"species\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74161c59-2606-4af2-b82f-864ee1d56030",
   "metadata": {},
   "source": [
    "# 数据集划分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b7fc7c6e-b486-4643-ae7d-7bbdf1c259a4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-10T11:27:44.352010400Z",
     "start_time": "2024-01-10T11:27:44.326957800Z"
    }
   },
   "outputs": [],
   "source": [
    "x = iris.values[:, :4]\n",
    "y = iris.values[:, -1]\n",
    "train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.5, random_state=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "da05879f-3f97-4ef8-ac9d-fdde9cc68104",
   "metadata": {},
   "outputs": [],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78d6f60d-0802-4226-87d1-6a20c7677ad9",
   "metadata": {},
   "outputs": [],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0335ddc2-a4ec-4065-8354-c8bfa4b2746a",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "test_x"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "42ddc6f5a3e34e68"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9d9abcbe-b57b-43a3-9116-f59410e1e4fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "test_y"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "3f0bf6af76226fea"
  },
  {
   "cell_type": "markdown",
   "id": "1d2ffcbb-bb70-408c-829b-faa350100383",
   "metadata": {},
   "source": [
    "# sklearn实现机器学习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b27c68ae-ce01-4c10-a57e-55ee640b5989",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-10T11:27:49.488622500Z",
     "start_time": "2024-01-10T11:27:49.478115100Z"
    }
   },
   "outputs": [],
   "source": [
    "lr = LogisticRegressionCV()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f03d2d55-c208-408f-8550-6478a333faf2",
   "metadata": {},
   "source": [
    "## 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c2710e79-2bd5-486b-bb6f-efa2147cb8e2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-10T11:27:53.129964800Z",
     "start_time": "2024-01-10T11:27:52.323270900Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "F:\\ProgramData\\anaconda3\\envs\\tensorflow\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n",
      "F:\\ProgramData\\anaconda3\\envs\\tensorflow\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n",
      "F:\\ProgramData\\anaconda3\\envs\\tensorflow\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n",
      "F:\\ProgramData\\anaconda3\\envs\\tensorflow\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n",
      "F:\\ProgramData\\anaconda3\\envs\\tensorflow\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n"
     ]
    },
    {
     "data": {
      "text/plain": "LogisticRegressionCV()",
      "text/html": "<style>#sk-container-id-1 {color: black;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>LogisticRegressionCV()</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">LogisticRegressionCV</label><div class=\"sk-toggleable__content\"><pre>LogisticRegressionCV()</pre></div></div></div></div></div>"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lr.fit(train_x, train_y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0e9af68-61d5-4299-bbac-2aa630287ccd",
   "metadata": {},
   "source": [
    "## 模型评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1b1a1a02-5ee9-446c-9b72-b957a5917245",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-01-10T11:27:57.383685300Z",
     "start_time": "2024-01-10T11:27:57.365648Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "0.9333333333333333"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lr.score(test_x, test_y)"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "## keras深度学习"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "e3c92cee8aedbcbd"
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [
    "# 在keras中需要对字符串热编码\n",
    "\n",
    "def one_host_encode(arr):\n",
    "    #获取目标值中左右类别并进行热编码\n",
    "    unique, ids = np.unique(arr, return_inverse=True)\n",
    "    return utils.to_categorical(ids, len(unique))\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:28:04.296403200Z",
     "start_time": "2024-01-10T11:28:04.287409400Z"
    }
   },
   "id": "a98ebeef67042b27"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [],
   "source": [
    "train_y_k = one_host_encode(train_y)\n",
    "test_y_k = one_host_encode(test_y)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:28:06.675697200Z",
     "start_time": "2024-01-10T11:28:06.652705300Z"
    }
   },
   "id": "390b1617cfb72fc3"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "train_y"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "dc5253b9cf917a8c"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "train_y_k"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "d99bbc88a6dcc931"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "test_y"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "cd81c992a7ecf607"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "test_y_k"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7769e53842474f72"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 构建模型"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "320cadc5a0296d3"
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [],
   "source": [
    "model = Sequential([\n",
    "    # 隐藏层,10个神经元，activation激活函数一般使用relu即可,input_shape输入的特征值shape\n",
    "    Dense(10, activation=\"relu\", input_shape=(4,)),\n",
    "    # 隐藏层\n",
    "    Dense(10, activation=\"relu\"),\n",
    "    # 输出层,3个神经元\n",
    "    Dense(3, activation=\"softmax\")\n",
    "])"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:28:08.654516300Z",
     "start_time": "2024-01-10T11:28:08.511036300Z"
    }
   },
   "id": "899a0e854f20dbf9"
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      " Layer (type)                Output Shape              Param #   \n",
      "=================================================================\n",
      " dense (Dense)               (None, 10)                50        \n",
      "                                                                 \n",
      " dense_1 (Dense)             (None, 10)                110       \n",
      "                                                                 \n",
      " dense_2 (Dense)             (None, 3)                 33        \n",
      "                                                                 \n",
      "=================================================================\n",
      "Total params: 193\n",
      "Trainable params: 193\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:28:13.402066100Z",
     "start_time": "2024-01-10T11:28:13.332038400Z"
    }
   },
   "id": "6520b2416ebb6655"
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "utils.plot_model(model, show_shapes=True)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:28:11.817417800Z",
     "start_time": "2024-01-10T11:28:11.573388Z"
    }
   },
   "id": "ba82b72a41a2ac02"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 模型预测"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "579d370cb5000f69"
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [],
   "source": [
    "# 模型编译\n",
    "model.compile(optimizer=\"adam\",  # 优化器\n",
    "              loss=\"categorical_crossentropy\",  # 损失函数：交叉双损失函数\n",
    "              metrics=[\"accuracy\"]  # 评价指标\n",
    "              )"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:50:50.852785900Z",
     "start_time": "2024-01-10T11:50:50.809987300Z"
    }
   },
   "id": "d6f36be23e3f87dd"
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [],
   "source": [
    "# 类型转换\n",
    "train_x_f = np.array(train_x, dtype=np.float32)\n",
    "test_x_f = np.array(test_x, dtype=np.float32)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:58:27.604508800Z",
     "start_time": "2024-01-10T11:58:27.579562Z"
    }
   },
   "id": "2f563ede34b4f439"
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2791 - accuracy: 0.9467\n",
      "Epoch 2/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2638 - accuracy: 0.9333\n",
      "Epoch 3/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2426 - accuracy: 0.9600\n",
      "Epoch 4/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2493 - accuracy: 0.9333\n",
      "Epoch 5/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2214 - accuracy: 0.9733\n",
      "Epoch 6/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2219 - accuracy: 0.9600\n",
      "Epoch 7/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.2024 - accuracy: 0.9467\n",
      "Epoch 8/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.1888 - accuracy: 0.9733\n",
      "Epoch 9/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.1913 - accuracy: 0.9600\n",
      "Epoch 10/10\n",
      "75/75 [==============================] - 0s 2ms/step - loss: 0.1771 - accuracy: 0.9467\n"
     ]
    },
    {
     "data": {
      "text/plain": "<keras.callbacks.History at 0x2402f79e280>"
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型训练\n",
    "model.fit(train_x_f,\n",
    "          train_y_k,\n",
    "          epochs=10,  # 10次\n",
    "          batch_size=1,  # 每次送入1个训练\n",
    "          verbose=1\n",
    "          )"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T11:59:51.413778Z",
     "start_time": "2024-01-10T11:59:49.683392900Z"
    }
   },
   "id": "558ecd9530b49cd6"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 模型评估"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7fbc148b75afe060"
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3/3 [==============================] - 0s 6ms/step - loss: 0.2621 - accuracy: 0.9200\n"
     ]
    }
   ],
   "source": [
    "loss, accuracy = model.evaluate(test_x_f, test_y_k, verbose=1)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T12:02:16.117594Z",
     "start_time": "2024-01-10T12:02:15.763372500Z"
    }
   },
   "id": "d76cc577d87271f8"
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "data": {
      "text/plain": "0.26211827993392944"
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "loss"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T12:02:54.034064400Z",
     "start_time": "2024-01-10T12:02:53.975637700Z"
    }
   },
   "id": "64a93ca850dce429"
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [
    {
     "data": {
      "text/plain": "0.9200000166893005"
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "accuracy"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-10T12:02:56.923159800Z",
     "start_time": "2024-01-10T12:02:56.870919800Z"
    }
   },
   "id": "2ead831dbf6733e2"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "327397312d1e8ab5"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
